﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace ECM7.NantContrib.Tasks.Wix
{
	internal class FileListBuilder
	{
		public void Execute(string filesResultPath, string foldersResultPath, string directoryRef, IEnumerable<IWixFolderElement> folders)
		{
			using (var writerFiles = InitWriter(filesResultPath))
			{
				writerFiles.WriteStartElement("ComponentGroup");
				writerFiles.WriteAttributeString("Id", "ProductComponents");

				using (var writerFolders = InitWriter(foldersResultPath))
				{
					writerFolders.WriteStartElement("DirectoryRef");
					writerFolders.WriteAttributeString("Id", directoryRef);

					foreach (var folder in folders)
					{
						ProcessFolder(folder, writerFiles, writerFolders);
					}

					writerFolders.WriteEndElement();

					CloseWriter(writerFolders);
				}

				writerFiles.WriteEndElement();
				CloseWriter(writerFiles);
			}

		}

		private static XmlTextWriter InitWriter(string fileName)
		{
			var writer = new XmlTextWriter(fileName, Encoding.UTF8) { Formatting = Formatting.Indented };

			writer.WriteStartDocument();
			writer.WriteStartElement("Wix", "http://schemas.microsoft.com/wix/2006/wi");
			writer.WriteStartElement("Fragment");

			return writer;
		}

		private static void CloseWriter(XmlTextWriter writer)
		{
			writer.WriteEndElement();
			writer.WriteEndElement();
		}

		private static void ProcessFolder(IWixFolderElement folder, XmlTextWriter writerFiles, XmlTextWriter writerFolders)
		{
			WriteFoldersRecursive(folder.Path, writerFolders, writerFiles, folder.FolderId, folder.FolderName);
		}

		private static void WriteFoldersRecursive(string path, XmlTextWriter writerFolders, XmlTextWriter writerFiles, string id, string name)
		{
			// запись о папке
			string folderId = string.IsNullOrWhiteSpace(id) ? string.Format("FOLDER_{0}", FormatGuid()) : id.Trim();
			string folderName = string.IsNullOrWhiteSpace(name) ? Path.GetFileName(path) : name.Trim();

			writerFolders.WriteStartElement("Directory");
			writerFolders.WriteAttributeString("Id", folderId);
			writerFolders.WriteAttributeString("Name", folderName);

			// запись о всех файлах
			string[] files = Directory.GetFiles(path);

			if (files.Any())
			{
				Guid componentId = Guid.NewGuid();
				string strComponentId = string.Format("Component{0}", FormatGuid(componentId));

				writerFiles.WriteStartElement("Component");
				writerFiles.WriteAttributeString("Id", strComponentId);
				writerFiles.WriteAttributeString("Guid", componentId.ToString());
				writerFiles.WriteAttributeString("DiskId", "1");
				writerFiles.WriteAttributeString("Directory", folderId);


				foreach (var file in files)
				{
					writerFiles.WriteStartElement("File");
					writerFiles.WriteAttributeString("Id", "FILE_" + FormatGuid());
					writerFiles.WriteAttributeString("Source", file);
					writerFiles.WriteEndElement();
				}

				writerFiles.WriteEndElement();
			}

			// обрабатываем вложенные папки
			foreach (var subfolder in Directory.GetDirectories(path))
			{
				WriteFoldersRecursive(subfolder, writerFolders, writerFiles, null, null);
			}

			writerFolders.WriteEndElement();
		}

		private static string FormatGuid(Guid? guid = null)
		{
			return guid.GetValueOrDefault(Guid.NewGuid()).ToString("N").ToUpper();
		}
	}
}
